{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit Remotes;

interface

uses Windows, SysUtils, GirderAPI;

const
  MAX_BUFFER_LENGTH = 255;
  MAJOR_VER = 1;
  MINOR_VER = 0;
  MICRO_VER = 0;

type
  TAHMRemote = class
  private
    FEnabled: Boolean;
  protected
    function GetReady: Boolean; virtual;
    function GetName: String; virtual;
    function GetVersion: String; virtual;
    function GetDescription: String; virtual;
    procedure SetEnabled(Enabled: Boolean);
    function Open: Boolean; virtual;
    procedure Close; virtual;
    function Start: Boolean; virtual;
    procedure Stop; virtual;
    procedure PopulateMappings; virtual;
  public
    constructor Create;
    property Name: String read GetName;
    property Version: String read GetVersion;
    property Description: String read GetDescription;
    property Ready: Boolean read GetReady;
    property Enabled: Boolean read FEnabled write SetEnabled;
    procedure Reset; virtual;
  end;

  TAHMRemoteDLL = class(TAHMRemote)
  private
    FDLLName: String;
    FDLLHandle: Integer;
  protected
    function GetReady: Boolean; override;
    function CheckDependencies: Boolean; virtual;
    procedure LoadDLL;
    procedure ConfigureDLL; virtual;
    procedure CleanupDLL; virtual;
    procedure UnloadDLL;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Reset; override;
    property DLLName: String read FDLLName write FDLLName;
  end;

  TAHMRemoteGirder = class(TAHMRemoteDLL)
  private
    FBuffer: array[0..MAX_BUFFER_LENGTH] of Char;
    FAPIFunctions: T_Functions;
  protected
    function GetName: String; override;
    function GetVersion: String; override;
    function GetDescription: String; override;
    function Open: Boolean; override;
    procedure Close; override;
    function Start: Boolean; override;
    procedure Stop; override;
    procedure ConfigureDLL; override;
    procedure CleanupDLL; override;
  public
    constructor Create;
  end;

implementation

uses Tray, Mapping, Utilities;

type
  // Girder Exported API method signatures
  TGirName = procedure(Buffer: PChar; Size: Integer); stdcall;
  TGirVersion = procedure(Buffer: PChar; Size: Integer); stdcall;
  TGirDescription = procedure(Buffer: PChar; Size: Integer); stdcall;
  TGirOpen = function(MajorVer, MinorVer, MicroVer: Integer; APIFunctions: Pointer): Integer; stdcall;
  TGirClose = function: Integer; stdcall;
  TGirStart = function: Integer; stdcall;
  TGirStop = function: Integer; stdcall;

var
  // Girder DLL method address pointers
  GirName: TGirName;
  GirVersion: TGirVersion;
  GirDescription: TGirDescription;
  GirOpen: TGirOpen;
  GirClose: TGirClose;
  GirStart: TGirStart;
  GirStop: TGirStop;

// Callback event method for receiving Girder DLL events
function GirSendEvent(eventstring: PChar; payload: pbytearray; len: Integer; device: Integer): Integer; stdcall;
begin
  MappingsInstance.HandleMessage(EventString);
  AHMMainForm.AnimateIcon;

  Result := 0;
end;

// TAHMRemote

constructor TAHMRemote.Create;
begin
  inherited Create;

  FEnabled := False;

  // Repopulate control to mediate mapping
  with MappingsInstance do
  begin
    BeginUpdate;
    ClearMappings;
    Self.PopulateMappings;
    EndUpdate;
  end;
end;

function TAHMRemote.GetReady: Boolean;
begin
  // Descendants may implement this if required
  Result := True;
end;

function TAHMRemote.GetName: String;
begin
  // Descendants may implement this if required
  Result := '';
end;

function TAHMRemote.GetVersion: String;
begin
  // Descendants may implement this if required
  Result := '';
end;

function TAHMRemote.GetDescription: String;
begin
  // Descendants may implement this if required
  Result := '';
end;

procedure TAHMRemote.SetEnabled(Enabled: Boolean);
begin
  if Enabled <> FEnabled then
  begin
    if Enabled then
    begin
      // Initialise
      if Open and Start then FEnabled := True;
    end
    else
    begin
      // Shutdown
      Stop;
      Close;
      FEnabled := False;
    end;
  end;
end;

function TAHMRemote.Open: Boolean;
begin
  // Descendants may implement this if required
  Result := True;
end;

procedure TAHMRemote.Close;
begin
  // Descendants may implement this if required
end;

function TAHMRemote.Start: Boolean;
begin
  // Descendants may implement this if required
  Result := True;
end;

procedure TAHMRemote.Stop;
begin
  // Descendants may implement this if required
end;

procedure TAHMRemote.Reset;
begin
  SetEnabled(False);
  SetEnabled(True);
end;

procedure TAHMRemote.PopulateMappings;
begin
  // Descendants may implement this as required
end;

// TAHMRemoteDLL

constructor TAHMRemoteDLL.Create;
begin
  inherited Create;

  // Initialise nil DLL method pointers
  UnloadDLL;
end;

destructor TAHMRemoteDLL.Destroy;
begin
  // Shutdown DLL cleanly
  SetEnabled(False);
  UnloadDLL;

  inherited Destroy;
end;

function TAHMRemoteDLL.GetReady: Boolean;
begin
  // Set default result - not ready yet
  Result := False;

  if CheckDependencies then
  begin
    // Load DLL and check for success
    LoadDLL;
    Result := FDLLHandle <> 0;
  end;

  // If we're not ready then disable DLL
  if not Result then SetEnabled(False);
end;

function TAHMRemoteDLL.CheckDependencies: Boolean;
begin
  // Descendants may implement this to determine any dependencies
  Result := True;
end;

procedure TAHMRemoteDLL.LoadDLL;
begin
  // Don't attempt to load DLL if already loaded
  if FDLLHandle <> 0 then Exit;

  // Attempt to load the required dll
  FDLLHandle := LoadLibrary(PAnsiChar(FDLLName));
  if FDLLHandle <> 0 then ConfigureDLL;
end;

procedure TAHMRemoteDLL.ConfigureDLL;
begin
  // Descendants may implement this to lookup DLL methods
end;

procedure TAHMRemoteDLL.CleanupDLL;
begin
  // Descendants may implment this to disconnect DLL methods
end;

procedure TAHMRemoteDLL.UnloadDLL;
begin
  CleanupDLL;

  if FDLLHandle <> 0 then FreeLibrary(FDLLHandle);
  FDLLHandle := 0;
end;

procedure TAHMRemoteDLL.Reset;
begin
  // Force reset & reloading of DLL
  SetEnabled(False);
  UnloadDLL;
  LoadDLL;
  SetEnabled(True);
end;

// TAHMRemoteGirder

constructor TAHMRemoteGirder.Create;
begin
  inherited;

  // Populate API structure
  FillChar(FAPIFunctions, SizeOf(T_Functions), 0);
  with FAPIFunctions do
  begin
    size := SizeOf(T_Functions);
    send_event := Addr(GirSendEvent);
  end;
end;

function TAHMRemoteGirder.GetName: String;
begin
  if @GirName <> nil then
  begin
    GirName(FBuffer, MAX_BUFFER_LENGTH);
    Result := FBuffer;
  end
  else
    Result := '';
end;

function TAHMRemoteGirder.GetVersion: String;
begin
  if @GirVersion <> nil then
  begin
    GirVersion(FBuffer, MAX_BUFFER_LENGTH);
    Result := FBuffer;
  end
  else
    Result := '';
end;

function TAHMRemoteGirder.GetDescription: String;
begin
  if @GirDescription <> nil then
  begin
    GirDescription(FBuffer, MAX_BUFFER_LENGTH);
    Result := FBuffer;
  end
  else
    Result := '';
end;

function TAHMRemoteGirder.Open: Boolean;
begin
  Result := (@GirOpen <> nil) and
            (GirOpen(MAJOR_VER, MINOR_VER, MICRO_VER, @FAPIFunctions) = GIR_TRUE);
end;

procedure TAHMRemoteGirder.Close;
begin
  // Close DLL
  if @GirOpen <> nil then GirClose;
end;

function TAHMRemoteGirder.Start: Boolean;
begin
  Result := (@GirStart <> nil) and (GirStart = GIR_TRUE);
end;

procedure TAHMRemoteGirder.Stop;
begin
  if @GirStop <> nil then GirStop;
end;

procedure TAHMRemoteGirder.ConfigureDLL;
begin
  inherited;

  // Get process address of interesting DLL methods
  @GirName        := GetProcAddress(FDLLHandle, 'gir_name');
  @GirVersion     := GetProcAddress(FDLLHandle, 'gir_version');
  @GirDescription := GetProcAddress(FDLLHandle, 'gir_description');
  @GirOpen        := GetProcAddress(FDLLHandle, 'gir_open');
  @GirClose       := GetProcAddress(FDLLHandle, 'gir_close');
  @GirStart       := GetProcAddress(FDLLHandle, 'gir_start');
  @GirStop        := GetProcAddress(FDLLHandle, 'gir_stop');
end;

procedure TAHMRemoteGirder.CleanupDLL;
begin
  inherited;

  // Remove stale DLL method pointers
  @GirName        := nil;
  @GirVersion     := nil;
  @GirDescription := nil;
  @GirOpen        := nil;
  @GirClose       := nil;
  @GirStart       := nil;
  @GirStop        := nil;
end;


end.
